import huck
import huck.api.user
import huck.api.user.manage
import hashlib
import logging
import pyrant
import uuid

class Manage(huck.api.user.manage.Abstract):

  def __init__(self, handler, type, prefix, salt, session_key, resource):
    super(Manage, self).__init__(handler, type)
    self.__prefix = prefix
    self.__salt = salt
    self.__session_key = session_key
    self.__resource = resource
    self.__is_setup = False

  def __setup(self):
    if not self.__is_setup:
      try:
        self.tyrant = huck.api.resource[self.__resource]
      except pyrant.TyrantError:
        logging.critical('unable to connect to tokyo tyrant')
        raise huck.api.user.manage.Error('unable to conntent to tokyo tyrant')
      except KeyError:
        logging.critical('tokyotyrant resource not setup')
        raise huck.api.user.manage.Error('tokyotyrant resource not setup')
      self.__is_setup = True

  def create(self, email, password, name, id=None):
    self.__setup()
    key = self.__key(email, id)
    if not key in self.tyrant:
      id = id or uuid.uuid4().get_hex()
      self.tyrant[key] = { 'id': id, 'email': email, 'password': self.__hash(password), 'name': name }
      self.tyrant['%s/id/%s' % (self.__prefix, id)] = email
      return True
    else:
      logging.info('create user failed because user already exists: %s' % key)
      raise huck.api.user.manage.UserExists('user already exists')

  def delete(self, id=None, email=None):
    self.__setup()
    key = self.__key(id, email)
    try:
      del self.tyrant[key]
      return True
    except KeyError:
      logging.info('delete user failed because user does not exist: %s' % key)

  def login(self, password, id=None, email=None):
    self.__setup()
    key = self.__key(email, id)
    try:
      user = self.tyrant[key]
      if user['password'] == self.__hash(password):
        self.handler.session.set('%s_id' % self.__session_key, user['id'])
        self.handler.session.set('%s_email' % self.__session_key, user['email'])
        self.handler.session.set('%s_name' % self.__session_key, user['name'])
        self.handler.session.save()
        return True
      else:
        logging.info('login attempt failed because of bad password: %s' % key)
    except KeyError:
      logging.info('login attempt failed because user does not exist: %s' % key)

  def logout(self):
    self.handler.session.delete('%s_id' % self.__session_key)
    self.handler.session.delete('%s_email' % self.__session_key)
    self.handler.session.delete('%s_name' % self.__session_key)
    self.handler.session.save()
    return True

  def __hash(self, password):
    return hashlib.sha256('%s.%s' % (self.__salt, password)).hexdigest()

  def __key(self, email, id):
    if email:
      return email
    elif id:
      try:
        return self.tyrant['%s/%s' % (self.__prefix, id)]
      except KeyError:
        logging.info('unable to lookup user by id: %s' % id)
        huck.api.user.manage.Error('unable to lookup user by id')
    else:
      logging.warn('email or id required to generate id')
      raise huck.api.user.manage.Error('email or id required')

class User(huck.api.user.SessionAbstract):
  pass

class Create(object):

  def __init__(self, type='default', login_url='/account/login', logout_url='/account/logout', prefix='/user', session_key='user', salt='huck', resource='pyrant'):
    self.type = type
    self.login_url = login_url
    self.logout_url = logout_url
    self.prefix = prefix
    self.session_key = session_key
    self.salt = salt
    self.resource = resource

  def setup(self, application):
    huck.api.user.set(User, self.type, login_url=self.login_url, logout_url=self.logout_url)
    huck.api.user.manage.set(Manage, self.type, prefix=self.prefix, session_key='user', salt=self.salt, resource=self.resource)
    return application
